package cn.jetpiece.cloud.joss.app.modular.accessor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.jetpiece.cloud.core.page.PageFactory;
import cn.jetpiece.cloud.joss.api.accossor.model.params.CreateAccessorParam;
import cn.jetpiece.cloud.joss.api.accossor.model.params.UpdateAccessorParam;
import cn.jetpiece.cloud.joss.api.accossor.model.query.AccessorQuery;
import cn.jetpiece.cloud.joss.api.accossor.model.result.AccessorResult;
import cn.jetpiece.cloud.joss.api.constant.AccessorCache;
import cn.jetpiece.cloud.joss.app.core.constant.OssConstants;
import cn.jetpiece.cloud.joss.app.modular.accessor.entity.Accessor;
import cn.jetpiece.cloud.joss.app.modular.accessor.mapper.AccessorMapper;
import cn.jetpiece.cloud.joss.app.modular.accessor.service.AccessorService;
import cn.jetpiece.cloud.joss.app.modular.accessor.wrapper.AccessorWrapper;
import cn.jetpiece.cloud.joss.app.modular.object.enums.BasicExceptionEnum;
import cn.jetpiece.cloud.model.exception.ServiceException;
import cn.jetpiece.cloud.model.page.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 授权 服务实现类
 * </p>
 *
 * @author XuJZ
 * @since 2020-09-05
 */
@Service
@AllArgsConstructor
public class AccessorServiceImpl extends ServiceImpl<AccessorMapper, Accessor> implements AccessorService {
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean add(CreateAccessorParam param) {
        LambdaQueryWrapper<Accessor> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Accessor::getAccessorName, param.getAccessorName());
        if (super.count(wrapper) > 0) {
            throw new ServiceException(BasicExceptionEnum.ACCESSOR_REPEAT);
        }
        Accessor bean = new Accessor();
        bean.setAccessKey(RandomUtil.randomString(16));
        bean.setSecretKey(RandomUtil.randomString(32));
        BeanUtil.copyProperties(param, bean);
        redisTemplate.boundHashOps(OssConstants.ACCESSOR).put(bean.getAccessKey(), BeanUtil.copyProperties(bean, AccessorCache.class));
        return super.save(bean);
    }

    @Override
    public boolean update(UpdateAccessorParam param) {
        Accessor oldBean = super.getById(param.getId());
        if (oldBean == null) {
            throw new ServiceException(BasicExceptionEnum.ACCESSOR_NOT_EXISTED);
        }
        if (StrUtil.isNotEmpty(param.getAccessorName())) {
            LambdaQueryWrapper<Accessor> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Accessor::getAccessorName, param.getAccessorName());
            wrapper.ne(Accessor::getId, param.getId());
            if (super.count(wrapper) > 0) {
                throw new ServiceException(BasicExceptionEnum.ACCESSOR_REPEAT);
            }
        }
        Accessor update = BeanUtil.copyProperties(param, Accessor.class);
        update.setId(param.getId());
        if (param.getChangeAccessKey() != null && param.getChangeAccessKey()) {
            update.setAccessKey(RandomUtil.randomString(16));
        }
        if (param.getChangeSecretKey() != null && param.getChangeSecretKey()) {
            update.setSecretKey(RandomUtil.randomString(32));
        }
        boolean result = super.updateById(update);
        if (result) {
            redisTemplate.boundHashOps(OssConstants.ACCESSOR).delete(oldBean.getAccessKey());
        }
        return result;
    }

    @Override
    public boolean delete(String id) {
        Accessor bean = super.getById(id);
        if (bean == null) {
            throw new ServiceException(BasicExceptionEnum.ACCESSOR_NOT_EXISTED);
        }
        boolean result = super.removeById(id);
        if (result) {
            redisTemplate.boundHashOps(OssConstants.ACCESSOR).delete(bean.getAccessKey());
        }
        return result;
    }


    @Override
    public PageResult<AccessorResult> page(AccessorQuery param) {
        LambdaQueryWrapper<Accessor> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(param.getId())) {
            wrapper.eq(Accessor::getId, param.getId());
        }
        if (StrUtil.isNotEmpty(param.getAccessorName())) {
            wrapper.like(Accessor::getAccessorName, param.getAccessorName());
        }
        if (StrUtil.isNotEmpty(param.getDefaultBucketName())) {
            wrapper.eq(Accessor::getDefaultBucketName, param.getDefaultBucketName());
        }
        if (StrUtil.isNotEmpty(param.getDefaultObjectPrefixPath())) {
            wrapper.like(Accessor::getDefaultObjectPrefixPath, param.getDefaultObjectPrefixPath());
        }
        if (StrUtil.isNotEmpty(param.getAccessKey())) {
            wrapper.like(Accessor::getAccessKey, param.getAccessKey());
        }
        if (param.getIsEnable() != null) {
            wrapper.eq(Accessor::getIsEnable, param.getIsEnable());
        }
        IPage<Accessor> iPage = PageFactory.defaultPage();
        IPage<Accessor> page = super.page(iPage, wrapper);
        return new AccessorWrapper(page).setWrapper(param.getWrapper()).wrapPageResult();
    }

    @Override
    public AccessorCache getByAccessKey(String accessKey) {
        if (StrUtil.isBlank(accessKey)) {
            return null;
        }
        AccessorCache accessorCache = (AccessorCache) redisTemplate.boundHashOps(OssConstants.ACCESSOR).get(accessKey);
        if (accessorCache == null) {
            LambdaQueryWrapper<Accessor> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Accessor::getAccessKey, accessKey);
            wrapper.eq(Accessor::getIsEnable, 1);
            Accessor accessor = getOne(wrapper);
            if (accessor == null) {
                return null;
            }
            accessorCache = BeanUtil.copyProperties(accessor, AccessorCache.class);
            redisTemplate.boundHashOps(OssConstants.ACCESSOR).put(accessKey, accessorCache);
        }
        return accessorCache;
    }
}
